﻿using AttributeRouting.Web.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using _2009035.Models;
using _2009035.Utilities;
using System.Web.Mvc;

namespace _2009035.Controllers
{
    //[RequireHttps]
    public class SearchController : Controller
    {
        private DbEntities ent = new DbEntities();


        public ActionResult AutoComplete(string term)
        {
            return Json(ent.Employees.Where(x => x.firstName.Contains(term) || x.lastName.Contains(term)).ToDictionary(x => x.employeeNumber, x => string.Format("{0} {1}", x.firstName, x.lastName)).ToArray(), JsonRequestBehavior.AllowGet);
        }


        /// <summary>
        /// This method is able to perform both authenticated and unauthenticated
        /// search. If the user is an administrator set a viewbag or a variable 
        /// that could be used on the client side to hide the rendering of the 
        /// salary and other sensitive details.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns>
        /// A JSON string of the search results based on a particular query.
        /// </returns>
        [AllowAnonymous]     
        [HttpPost]
        public JsonResult StandardSearch(Request request)
        {
            ViewBag.StandardSearch = "Standard Search performed";
            IEnumerable<Employee> employees = null;
           
            // check for the gender of the employee first
            employees = ent.Employees.AsEnumerable();

            if (request.searchDepartment != Departments.All.ToString())
            {
                this.GetEmployeeBasedOnDepartment(ref employees, request.searchDepartment, request.searchDepartmentNumber, request.searchOldEmployee);
            }

            if ((!string.IsNullOrEmpty(request.searchGender)) && (!string.IsNullOrEmpty(request.searchTitle)))
            {
                if (request.searchGender != Gender.Both.ToString())
                {
                    this.GetEmployeeBasedOnGender(request.searchGender, ref employees);
                }

                if (request.searchTitle != Titles.All.ToString())
                {
                    GetEmployeeBasedOnTitle(request.searchTitle, ref employees);
                }
            }
           
            return PerformLowLevelSearch(request, employees);
        }

        [AllowAnonymous]     
        [HttpPost]
        public JsonResult UnauthenticatedSearch(Request request)
        {
            IEnumerable<Employee> employees = ent.Employees;
            return PerformLowLevelSearch(request, employees);
        }


        /// <summary>
        /// Posts the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public HttpResponseMessage Post(int id)
        {
            HttpRequestBase _request = this.HttpContext.Request;
           
            // create a response message to send back
            var response = new HttpResponseMessage();
            Employee employeeToUpdate = null;
            try
            {
                // select the employee from the database where the id
                // matches the one passed in at api/employees/id

                employeeToUpdate = ent.Employees.FirstOrDefault(x => x.employeeNumber == id);

                if (employeeToUpdate != null)
                {
                    // update the employee object handling null values or empty strings

                    employeeToUpdate.lastName = string.IsNullOrEmpty(_request["lastName"]) ? employeeToUpdate.lastName : _request["lastName"];
                    employeeToUpdate.firstName = string.IsNullOrEmpty(_request["firstName"]) ? employeeToUpdate.firstName : _request["firstName"];
                    employeeToUpdate.gender = string.IsNullOrEmpty(_request["gender"]) ? employeeToUpdate.gender : _request["gender"];
                    ent.SaveChanges();
                    response.StatusCode = HttpStatusCode.OK;
                }
                else
                {
                    // with some more info.
                    response.StatusCode = HttpStatusCode.InternalServerError;
                    response.Content = new StringContent(string.Format("The employee with id {0} was not found in the database", id.ToString()));
                }
            }

            catch (Exception ex)
            {
                // something went wrong - possibly a database error. return a
                // 500 server error and send the details of the exception.
                response.StatusCode = HttpStatusCode.InternalServerError;
                response.Content = new StringContent(string.Format("The database updated failed: {0}", ex.Message));
            }

            // return the HTTP Response.
            return response;
        }

        /// <summary>
        /// Gets the employee based on gender.
        /// </summary>
        /// <param name="gender">The gender.</param>
        /// <param name="employee">The employee.</param>
        private void GetEmployeeBasedOnGender(string gender, ref IEnumerable<Employee> employee)
        {
            // check if the gender is not both
            employee = employee.Where(x => x.gender == gender);
        }

        /// <summary>
        /// Gets the employee based on department.
        /// </summary>
        /// <param name="department">The department.</param>
        /// <param name="employee">The employee.</param>
        private void GetEmployeeBasedOnDepartment(ref IEnumerable<Employee> employee, string department = null, string departmentNumber = null, bool searchOld = false)
        {
            // string departmentConverted = Utility.GetEnumDescription(department);
            string deptNo = string.Empty;
            deptNo = (!string.IsNullOrEmpty(department)) ? ent.Departments.FirstOrDefault(x => x.departmentName == department).departmentNumber : departmentNumber;
            var allEmployees = ent.DepartmentEmployees.Where(x => x.departmentNumber == deptNo);

            if (searchOld == true)
            {
                allEmployees = allEmployees.Where(x => x.toDate < Constants.EndDateAsCurrent);
            }

            employee = allEmployees.Select(g => g.Employee);
        }

        private void GetEmployeeBasedOnTitle(string title, ref IEnumerable<Employee> employee)
        {
            // string titleConverted = Utility.GetEnumDescription(title);
            employee = ent.Titles.Where(x => x.title1 == title).Select(g => g.Employee);
        }

        /// <summary>
        /// Performs the low level search.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="employees">The employees.</param>
        /// <returns></returns>
        private JsonResult PerformLowLevelSearch(Request request, IEnumerable<Employee> employees)
        {
            System.Func<Employee, GridEmployee> selector = null;
            
            if(this.User.Identity.IsAuthenticated == true)
            {
                selector = x => new GridEmployee() { employeeNumber = x.employeeNumber, firstName = x.firstName, lastName = x.lastName, gender = x.gender, birthDate = x.birthDate, hireDate = x.hireDate };
            }
            else
            {
                selector = x => new GridEmployee() { employeeNumber = x.employeeNumber, firstName = x.firstName, lastName = x.lastName, gender = x.gender };
            }

            
         
            IQueryable<GridEmployee> employeeQuery = null;

            if (!string.IsNullOrEmpty(request.searchTerm))
            {
                string[] splitName = request.searchTerm.ToLower().Split(' ');
                string firsName = splitName[0];
                string lastName = (splitName.Length > 1) ? splitName[1] : firsName;

                // refine based on the name first
                if (splitName.Length > 1)
                {
                    employees = employees.Where(x => x.firstName.ToLower().Contains(firsName) && x.lastName.ToLower().Contains(lastName));
                }
                else
                {
                    employees = employees.Where(x => x.firstName.ToLower().Contains(firsName) || x.lastName.ToLower().Contains(lastName));
                }
               
            }

            employeeQuery = employees.Select(selector).Skip(request.skip).Take(request.take).AsQueryable();

            // return employeeQuery in the form of a response object
            return Json(new Response(employeeQuery.ToArray(), employees.Count()), JsonRequestBehavior.AllowGet);
        }

        protected override void Dispose(bool disposing)
        {
            ent.Dispose();
            base.Dispose(disposing);
        }
    }
}
